<script>
import mqtt from 'mqtt'
import { mqttConnection } from '@/utils/constant'
// import { mergeDevicesStates } from '@/utils/device'
import { generateRandStr, getCurrentTime, isJson, uniqueArr, parseTime } from '@/utils'
import { mapGetters } from 'vuex'
export default {
  data() {
    return {
      // devices: this.$store.getters.devicesObj,
      // serialnos: this.$store.getters.devices.map(val => (val.rtu_serialno || val.serialno)),
      connection: mqttConnection,
      subscription: {
        topic: 'D/0103.0007.2038000000/#',
        qos: 0
      },
      publish: {
        topic: 'topic/browser',
        qos: 0,
        payload: '{ "msg": "Hello, I am browser." }'
      },
      receiveNews: '',
      qosList: [
        { label: 0, value: 0 },
        { label: 1, value: 1 },
        { label: 2, value: 2 }
      ],
      client: {
        connected: false
      },
      subscribeSuccess: false
    }
  },
  computed: {
    ...mapGetters(['topics', 'devices', 'devicesObj']),
    serialnos() {
      const rtu_serialnos = this.devices.map(val => val.rtu_serialno).filter((val) => { return val })
      const serialnos = this.devices.map(val => val.serialno)
      return uniqueArr(rtu_serialnos).concat(serialnos)
    },
    serialnosMap() {
      const res = {}
      this.devices.forEach((val) => {
        const temp = val.rtu_serialno || val.serialno
        if (!res[temp]) {
          res[temp] = [val.serialno]
        } else {
          res[temp].push(val.serialno)
        }
      })
      return res
    }
  },
  mounted() {
    this.createConnection()
  },
  methods: {
    // 创建连接
    createConnection() {
      // 连接字符串, 通过协议指定使用的连接方式
      // ws 未加密 WebSocket 连接
      // wss 加密 WebSocket 连接
      // mqtt 未加密 TCP 连接
      // mqtts 加密 TCP 连接
      // wxs 微信小程序连接
      // alis 支付宝小程序连接
      const { host, port, endpoint, ...options } = this.connection
      options.clientId = 'mqttjs_3be2c321' + generateRandStr()
      // const connectUrl = `wss://${host}:${port}${endpoint}`
      const connectUrl = `wss://${host}:${port}${endpoint}`
      // const connectUrl = `ws://10.18.1.230:8001/mqtt`
      try {
        if (!this.client.connected) {
          this.client = mqtt.connect(connectUrl, options)
        }
      } catch (error) {
        console.log('mqtt.connect error', error)
      }
      this.client.on('connect', () => {
        console.log('Connection succeeded!')
        this.client.connected = true
        this.doSubscribe()
      })
      this.client.on('error', error => {
        console.log('Connection failed', error)
        this.doUnSubscribe()
      })
      this.client.on('message', (topic, message) => {
        const serialno = topic.split('/').pop()
        const type = topic.split('/')[3]
        const state_raw = this.Utf8ArrayToStr(message)
        const state =
          typeof state_raw === 'string' && isJson(state_raw)
            ? JSON.parse(state_raw)
            : {}
        if (['STS', 'LIVENESS'].includes(type) && state && this.serialnos.includes(serialno)) {
          /**
           * 1.根据设备编号筛选出来设备
           * 2.将设备编号和更新后的设备状态组成对象
           * 3.更新原设备列表状态
           * 4.将更新后的设备列表推送到VUEX中
           */
          this.serialnosMap[serialno].forEach((item) => {
            const device = this.devicesObj[item]
            if (device && device.states) {
              Object.assign(device.states, state.regs)
              if (type === 'LIVENESS') {
                Object.assign(device.states, state)
              }
              if (state.datatime) {
                Object.assign(device.states, { datatime: state.datatime })
              }
              if (state.regs) {
                let datatime = getCurrentTime()
                if (state.regs.datatime) {
                  datatime = parseTime(state.regs.datatime)
                }
                Object.assign(device.states, { datatime })
              }
              this.$store.commit('device/SET_DEVICE', device)
            }
          })
        }
      })
    },
    doSubscribe() {
      if (!this.subscribeSuccess) {
        const { qos } = this.subscription
        this.topics.forEach((ctopic) => {
          this.client.subscribe(ctopic, qos, (error, res) => {
            if (error) {
              console.log('Subscribe to topics error', error)
              return
            }
            this.subscribeSuccess = true
            console.log('Subscribe to topics res', res)
          })
        })
      }
    },
    doUnSubscribe() {
      const { topic } = this.subscription
      this.client.unsubscribe(topic, error => {
        if (error) {
          console.log('Unsubscribe error', error)
        }
      })
    },
    doPublish() {
      const { topic, qos, payload } = this.publication
      this.client.publish(topic, payload, qos, error => {
        if (error) {
          console.log('Publish error', error)
        }
      })
    },
    destroyConnection() {
      if (this.client.connected) {
        try {
          this.client.end()
          this.client = {
            connected: false
          }
          console.log('Successfully disconnected!')
        } catch (error) {
          console.log('Disconnect failed', error.toString())
        }
      }
    },
    Utf8ArrayToStr(array) {
      var out, i, len, c
      var char2, char3

      out = ''
      len = array.length
      i = 0
      while (i < len) {
        c = array[i++]
        switch (c >> 4) {
          case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
            // 0xxxxxxx
            out += String.fromCharCode(c)
            break
          case 12: case 13:
            // 110x xxxx 10xx xxxx
            char2 = array[i++]
            out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F))
            break
          case 14:
            // 1110 xxxx 10xx xxxx 10xx xxxx
            char2 = array[i++]
            char3 = array[i++]
            out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0))
            break
        }
      }

      return out
    }
  },
  // eslint-disable-next-line vue/require-render-return
  render(h, context) { }
}
</script>
